home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume24 / qterm5.0 / part01 next >
Encoding:
Internet Message Format  |  1991-03-21  |  53.1 KB

  1. Subject:  v24i082:  Qterm5.0 -- Query terminal for its type, Part01/02
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: 23817b14 f66cb394 106806de f16726fa
  5.  
  6. Submitted-by: "Michael A. Cooper" <mcooper@usc.edu>
  7. Posting-number: Volume 24, Issue 82
  8. Archive-name: qterm5.0/part01
  9.  
  10. Qterm is a program that queries terminals to find out what kind of
  11. terminal is responding.  It is useful to automagically define your
  12. terminal type.  It prints the name of the terminal (compatible,
  13. hopefully, with a termcap/terminfo name) such as "vt100" to standard
  14. output.  See the manual for details.
  15.  
  16. The major changes in these version of qterm is a re-write of command
  17. line parsing and the options qterm accepts.  I've written a new,
  18. "generic" command line parsing package called "options" which is
  19. included as part of this distribution of qterm.  (See the options.3
  20. man page for details on programming with the options package.)  Qterm
  21. now has a totally new set of (hopefully) clear and concise options.
  22. The old command line options are still accepted if qterm is compiled
  23. with OPT_COMPAT defined (see Makefile).  WARNING: Some of the old
  24. options conflict with the new options.  i.e.  If OPT_COMPAT is
  25. defined, "qterm -file foo" does not do what you think it will.  This
  26. is parsed as "qterm -f ile foo".
  27.  
  28. Qterm was written under 4.[23] BSD and will probably run without
  29. modification on other Berkeley Unix systems.  This version has also
  30. been tested under UTS 2.1 which is a System V.3 derivative.  It was
  31. compiled with "USG5" defined and setting $(LIBS) to "-lPW".  (See
  32. Makefile for more info).  It should work on other System V platforms.
  33.  
  34. #! /bin/sh
  35. # This is a shell archive.  Remove anything before this line, then feed it
  36. # into a shell via "sh file" or similar.  To overwrite existing files,
  37. # type "sh file -c".
  38. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  39. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  40. # Contents:  README options.3 options.c options.h qterm.c
  41. # Wrapped by rsalz@litchi.bbn.com on Fri Mar 22 12:25:37 1991
  42. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  43. echo If this archive is complete, you will see the following message:
  44. echo '          "shar: End of archive 1 (of 2)."'
  45. if test -f 'README' -a "${1}" != "-c" ; then 
  46.   echo shar: Will not clobber existing file \"'README'\"
  47. else
  48.   echo shar: Extracting \"'README'\" \(2200 characters\)
  49.   sed "s/^X//" >'README' <<'END_OF_FILE'
  50. X
  51. X        Q T E R M  -  Q U E R Y   T E R M I N A L
  52. X
  53. X                Version 5.0
  54. X
  55. XQterm is a program that queries terminals to find out what kind of
  56. Xterminal is responding.  It is useful to automagically define your
  57. Xterminal type.  It prints the name of the terminal (compatible,
  58. Xhopefully, with a termcap/terminfo name) such as "vt100" to standard
  59. Xoutput.  See the manual for details.
  60. X
  61. XThe major changes in these version of qterm is a re-write of command
  62. Xline parsing and the options qterm accepts.  I've written a new,
  63. X"generic" command line parsing package called "options" which is
  64. Xincluded as part of this distribution of qterm.  (See the options.3
  65. Xman page for details on programming with the options package.)  Qterm
  66. Xnow has a totally new set of (hopefully) clear and concise options.
  67. XThe old command line options are still accepted if qterm is compiled
  68. Xwith OPT_COMPAT defined (see Makefile).  WARNING: Some of the old
  69. Xoptions conflict with the new options.  i.e.  If OPT_COMPAT is
  70. Xdefined, "qterm -file foo" does not do what you think it will.  This
  71. Xis parsed as "qterm -f ile foo".
  72. X
  73. XQterm was written under 4.[23] BSD and will probably run without
  74. Xmodification on other Berkeley Unix systems.  This version has also
  75. Xbeen tested under UTS 2.1 which is a System V.3 derivative.  It was
  76. Xcompiled with "USG5" defined and setting $(LIBS) to "-lPW".  (See
  77. XMakefile for more info).  It should work on other System V platforms.
  78. X
  79. XIt has been running at one point or another here at USC on:
  80. X
  81. X    Sun-3, Sun-4, Sun386i's under SunOS 3.X, 4.0, 4.0.3, 4.1, 4.1.1
  82. X    Alliant's under Concentrix 3.X, 4.X, 5.X
  83. X    IBM RT's under ACIS 4.2 and 4.3
  84. X    DEC VAX & DEC RISC under Ultrix 2.2, 3.1, 4.0, 4.1
  85. X    4.[23]BSD (VAX)
  86. X    4.3BSD [MORE/bsd] (HP)
  87. X    Amdahl UTS (System V.3) 2.1
  88. X
  89. XIf you have Internet access, the latest and greatest version of qterm
  90. Xis available from "usc.edu" via anonymous ftp in the file
  91. X/pub/qterm.shar.  I update this file whenever there are any changes,
  92. Xso it's bound to be newer than a copy from any other source.
  93. X
  94. X
  95. XMichael A. Cooper, University Computing Services, U of Southern California
  96. X  INTERNET: mcooper@usc.edu                PHONE: 213-740-2957
  97. X  UUCP: ...!uunet!usc!mcooper              BITNET: mcooper@gamera
  98. END_OF_FILE
  99.   if test 2200 -ne `wc -c <'README'`; then
  100.     echo shar: \"'README'\" unpacked with wrong size!
  101.   fi
  102.   # end of 'README'
  103. fi
  104. if test -f 'options.3' -a "${1}" != "-c" ; then 
  105.   echo shar: Will not clobber existing file \"'options.3'\"
  106. else
  107.   echo shar: Extracting \"'options.3'\" \(7383 characters\)
  108.   sed "s/^X//" >'options.3' <<'END_OF_FILE'
  109. X.\"
  110. X.\" Copyright (c) 1990 Michael A. Cooper.
  111. X.\" This software may be freely distributed provided it is not sold for 
  112. X.\" profit and the author is credited appropriately.
  113. X.\"
  114. X.\" $Header: /src/common/usc/lib/libgen/RCS/options.3,v 1.4 1991/02/22 02:30:06 mcooper Exp $
  115. X.\"
  116. X.TH PARSEOPTIONS 3 "30 October 1990"
  117. X.ds ]W USC-UCS
  118. X.SH NAME
  119. XParseOptions, UsageOptions, HelpOptions, Num_Opts \- Parse command line options
  120. X.SH SYNOPSIS
  121. X.LP
  122. X.nf
  123. X.ft B
  124. X#include "/usr/usc/include/options.h"
  125. X.ft
  126. X.fi
  127. X.LP
  128. X.nf
  129. X.ft B
  130. Xint ParseOptions(options, num_options, argc, argv)
  131. XOptionDescRec *options;
  132. Xint num_options;
  133. Xint argc;
  134. Xchar **argv;
  135. X.ft
  136. X.fi
  137. X.LP
  138. X.nf
  139. X.ft B
  140. Xvoid UsageOptions(options, num_options, badoption)
  141. XOptionDescRec *options;
  142. Xint num_options;
  143. Xchar *badoption;
  144. X.ft
  145. X.fi
  146. X.LP
  147. X.nf
  148. X.ft B
  149. Xvoid HelpOptions(options, num_options, message)
  150. XOptionDescRec *options;
  151. Xint num_options;
  152. Xchar **message;
  153. X.ft
  154. X.fi
  155. X.LP
  156. X.nf
  157. X.ft B
  158. Xint Num_Opts(options)
  159. XOptionDescRec *options;
  160. X.ft
  161. X.fi
  162. X.LP
  163. X.nf
  164. X.ft B
  165. Xextern char *OptionChars;
  166. Xextern char *ProgramName;
  167. X.ft
  168. X.fi
  169. X.SH DESCRIPTION
  170. X.LP
  171. X.BR ParseOptions(\|)
  172. Xparses a given set of options found in
  173. X.B argv.
  174. XThe
  175. X.B argc
  176. Xparameter is the count of the number of string pointers
  177. Xin 
  178. X.B argv.
  179. XBoth 
  180. X.B argc
  181. Xand
  182. X.B argv
  183. Xare typically passed directly from a
  184. X.B main(\|)
  185. Xfunction.
  186. XThe
  187. X.B argv
  188. Xparameter should contain an array of strings that
  189. Xneed to be parsed.
  190. X.B ParseOptions(\|)
  191. Xreturns the number of entries in
  192. X.B argv
  193. Xthat were successfully parsed or -1 upon error.
  194. X.LP
  195. XThe
  196. X.B options
  197. Xstructure should contain a valid description list of options.
  198. XThe type
  199. X.B OptionDescRec
  200. Xis defined as the following in the
  201. X.B "options.h"
  202. Xheader file:
  203. X.RS
  204. X.LP
  205. X.nf
  206. X.ft B
  207. Xtypedef struct {
  208. X    char      *option;     /* Option string in argv */
  209. X    int       flags;       /* Flag bits */
  210. X    int       (*cvtarg)(); /* Function to convert argument */
  211. X    caddr_t   valp;        /* Variable to set */
  212. X    caddr_t   value;       /* Default value to provide */
  213. X    char      *usage;      /* Usage message */
  214. X    char      *desc;       /* Description message */
  215. X} OptionDescRec, *OptionDescList;
  216. X.ft R
  217. X.fi
  218. X.RE
  219. X.LP
  220. XThe order of
  221. X.I options
  222. Xis important because
  223. Xthe first partial match found in
  224. X.I options 
  225. Xis used.
  226. XThis allows abbreviations (except if the option is a
  227. X.I StickArg
  228. X[see below]).
  229. XFor instance, a user may specify only "\-n" for "\-number" provided
  230. Xthat "\-n" is unique to
  231. X.I options
  232. Xor that "\-number" is placed before any other "\-n*" options in
  233. X.I options.
  234. X.LP
  235. XThe
  236. X.I option
  237. Xmember of
  238. X.B OptionDescRec
  239. Xis the string name of the option.
  240. XThis is typically something like
  241. X.RS
  242. X.ft B
  243. X.nf
  244. X.sp
  245. X"\-c"
  246. X"+c"
  247. X"\-file"
  248. X.fi
  249. X.sp
  250. X.ft
  251. X.RE
  252. XThe first character of 
  253. X.I option
  254. Xis special.  It must be one of the characters know to be the
  255. Xstart of an option.
  256. XThe default list of starting option characters is "\-+".
  257. XThis indicates that an option can start with either a "\-" or
  258. Xa "+".  This list of characters may be changed by setting
  259. Xthe variable
  260. X.B OptionChars
  261. Xto point to a string of custom starting option characters.
  262. X.LP
  263. XThe
  264. X.I flags
  265. Xmember is used to set bits to describe how an option
  266. Xis to be interpreted.
  267. XValid flags are defined in the
  268. X.I "options.h"
  269. Xheader file:
  270. X.RS
  271. X.IP NoArg
  272. XNo argument for this option.  
  273. XUse the value in 
  274. X.I OptionDescRec.value 
  275. Xto set the value in the
  276. X.I valp
  277. Xmember of 
  278. X.B OptionDescRec.
  279. X.IP IsArg
  280. XValue is the option string itself.
  281. X.IP SepArg
  282. XValue is in next argument in argv.
  283. X.IP StickyArg
  284. XValue is the characters immediately following 
  285. Xthe option.
  286. X.IP SkipArg
  287. XIgnore this option and the next argument in argv.
  288. X.IP SkipLine
  289. XIgnore this option and the rest of argv.
  290. X.IP SkipNArgs
  291. XIgnore this option and the next 
  292. X.I OptionDescRes.value 
  293. Xarguments in argv.
  294. X.IP ArgHidden
  295. XDon't show this option in usage or help messages.
  296. X.RE
  297. X.LP
  298. XThe next member of
  299. X.B OptionDescRec
  300. Xis
  301. X.I cvtarg.
  302. XThis should be a pointer to a function that knows how to
  303. Xconvert the given argument into the correct type.
  304. XThe predefined functions are as follows:
  305. X.RS
  306. X.IP OptBool
  307. XConverts a boolean.
  308. X.IP OptInt
  309. XConverts an integer.
  310. X.IP OptShort
  311. XConverts a short.
  312. X.IP OptLong
  313. XConverts a long.
  314. X.IP OptStr
  315. XConverts a string.
  316. X.RE
  317. X.LP
  318. XThe
  319. X.I valp
  320. Xmember should be a pointer
  321. Xto the variable that needs to be set.
  322. X.I valp
  323. Xshould accept whatever type
  324. X.I cvtarg
  325. Xis expected to return.
  326. X.LP
  327. XThe
  328. X.I value
  329. Xmember should contain a default value to
  330. Xbe used if no value is given for an option or
  331. Xthis type of option does not require an argument
  332. X(according to the 
  333. X.I flags
  334. Xbits).
  335. XIf 
  336. X.I value 
  337. Xis
  338. X.B NULL
  339. Xthen an argument for this option
  340. Xis optional.
  341. X.LP
  342. X.I usage
  343. Xis used to build usage and help messages.
  344. XIt should be a string containing a description of any arguments
  345. Xthat may be used for this option.
  346. XThe option string itself should not be a part of 
  347. X.I usage.
  348. XThe 
  349. X.B UsageOptions(\|)
  350. Xand 
  351. X.B HelpOptions(\|)
  352. Xfunctions combine the
  353. X.I option
  354. Xfield with
  355. X.I usage
  356. Xand interpret the
  357. X.I flags
  358. Xbits to build a usage string.
  359. XIf this field is 
  360. X.B NULL,
  361. Xthen just the
  362. X.I option
  363. Xfield itself is used for usage and help messages.
  364. X.LP
  365. XThe
  366. X.I desc
  367. Xmember is used to build a help message for this option.
  368. XThis should be a string containing a brief description on what this
  369. Xoption does.
  370. X.LP
  371. XThe
  372. X.B num_options
  373. Xparameter should be the number of 
  374. X.B OptionDescRec's
  375. Xfound in 
  376. X.B options.
  377. XThe function
  378. X.BR Num_Opts(\|)
  379. Xwill return the number of 
  380. X.B OptionDescRec's.
  381. X.LP
  382. XThe
  383. X.B UsageOptions(\|)
  384. Xfunction
  385. Xprints a usage message.
  386. XIf
  387. X.I badoption
  388. Xis not 
  389. X.B NULL, 
  390. Xthen an initial message is displayed indicating that 
  391. X.I badoption
  392. Xis not a valid option.
  393. X.LP
  394. XThe
  395. X.B HelpOptions(\|)
  396. Xfunction
  397. Xprints a nicely formatted message describing all options.
  398. XIf
  399. X.I message
  400. Xis not 
  401. X.B NULL
  402. Xit is taken to be a message that is displayed in the output of
  403. Xa "\-help" option.
  404. X.SH EXAMPLE
  405. X.LP
  406. XHere is an example program:
  407. X.nf
  408. X.sp
  409. X.ft B
  410. X#include "options.h"
  411. X
  412. Xchar *filename = NULL;
  413. Xint number = \-1;
  414. Xint foo = \-1;
  415. Xint I = \-1;
  416. Xlong L = \-1;
  417. Xshort S = \-1;
  418. X
  419. XOptionDescRec opts[] = {
  420. X    {"\-foo",    NoArg,        OptBool, (caddr_t) &foo,    "0",
  421. X     (char *)NULL,    "Disable foo bar"},
  422. X    {"+foo",    NoArg,        OptBool, (caddr_t) &foo,           "1",
  423. X     (char *)NULL,    "Enable foo bar"},
  424. X    {"\-I",    StickyArg,    OptInt, (caddr_t) &I,        (caddr_t) NULL,
  425. X     (char *)NULL,    "Set value of I"},
  426. X    {"\-L",    StickyArg,    OptLong, (caddr_t) &L,        (caddr_t) NULL,
  427. X     (char *)NULL,    "Set value of L"},
  428. X    {"\-S",    SepArg,        OptShort, (caddr_t) &S,        (caddr_t) NULL,
  429. X     (char *)NULL,    "Set value of S"},
  430. X    {"\-C",    StickyArg,    OptStr, (caddr_t) &filename,    (caddr_t) NULL,
  431. X     (char *)NULL,    "Alternate file to use"},
  432. X    {"\-number",    SepArg,     OptInt, (caddr_t) &number,    "66",
  433. X     "interval",    NULL},
  434. X    {"\-file",    SepArg,     OptStr, (caddr_t) &filename,    (caddr_t) NULL,
  435. X     "filename",    "Specify alternate file to use"},
  436. X};
  437. X
  438. Xmain(argc, argv)
  439. X     int argc;
  440. X     char **argv;
  441. X{
  442. X    int c;
  443. X
  444. X    c = ParseOptions(opts, Num_Opts(opts), argc, argv);
  445. X    printf("Count = %d of %d\n", c, argc);
  446. X}
  447. X.ft
  448. X.fi
  449. X.SH "RETURN VALUES"
  450. X.B ParseOptions(\|)
  451. Xreturns the number of arguments parsed or -1 upon error.
  452. X.SH NOTES
  453. X.LP
  454. XThe
  455. X.I \-help
  456. Xoption is automatically built into 
  457. X.B ParseOptions(\|).
  458. X.LP
  459. XAll error messages are sent to 
  460. X.B stderr.
  461. X.LP
  462. XAn option may be both 
  463. X.I StickyArg
  464. Xand
  465. X.I SepArg.
  466. XIf both are set for one option, preference is given to
  467. X.I SepArg
  468. Xparsing.
  469. XAlso, no appreviations are allowed.
  470. X.SH AUTHOR
  471. XMichael A. Cooper, 
  472. X.br
  473. XUniversity Computing Services, 
  474. X.br
  475. XUniversity of Southern California.
  476. END_OF_FILE
  477.   if test 7383 -ne `wc -c <'options.3'`; then
  478.     echo shar: \"'options.3'\" unpacked with wrong size!
  479.   fi
  480.   # end of 'options.3'
  481. fi
  482. if test -f 'options.c' -a "${1}" != "-c" ; then 
  483.   echo shar: Will not clobber existing file \"'options.c'\"
  484. else
  485.   echo shar: Extracting \"'options.c'\" \(10901 characters\)
  486.   sed "s/^X//" >'options.c' <<'END_OF_FILE'
  487. X/*
  488. X * Copyright (c) 1990 Michael A. Cooper.
  489. X * This software may be freely distributed provided it is not sold for 
  490. X * profit and the author is credited appropriately.
  491. X */
  492. X
  493. X#ifndef lint
  494. Xstatic char *RCSid = "$Header: /am/sol/src/common/usc/lib/libgen/RCS/options.c,v 1.13 90/12/15 18:13:28 mcooper Exp $";
  495. X#endif
  496. X
  497. X/*
  498. X * $Log:    options.c,v $
  499. X * Revision 1.13  90/12/15  18:13:28  mcooper
  500. X * Add copywrite notice.
  501. X * 
  502. X * Revision 1.12  90/12/15  17:51:46  mcooper
  503. X * Add #ifdef HAS_VARARGS around include for <varargs>.
  504. X * 
  505. X * Revision 1.11  90/11/13  16:39:28  mcooper
  506. X * Add #ifdef HAS_VARARGS for systems without
  507. X * varargs.
  508. X * 
  509. X * Revision 1.10  90/11/13  15:28:01  mcooper
  510. X * - Add OptBool cvtarg routine.
  511. X * - Print default values in HelpOptions() 
  512. X *   when appropriate.
  513. X * 
  514. X * Revision 1.9  90/11/13  15:19:00  mcooper
  515. X * Added supported for options being both
  516. X * SepArg and StickyArg.
  517. X * 
  518. X * Revision 1.8  90/10/30  21:02:31  mcooper
  519. X * Need to exit() if -help is specified.
  520. X * 
  521. X * Revision 1.7  90/10/30  20:24:33  mcooper
  522. X * Fixed bug in UsageString().
  523. X * 
  524. X * Revision 1.6  90/10/30  19:53:05  mcooper
  525. X * Cleaned up some NeXT cc and lint stuff.
  526. X * 
  527. X * Revision 1.5  90/10/30  19:45:31  mcooper
  528. X * Remove unneeded paramter to HelpOptions().
  529. X * 
  530. X * Revision 1.4  90/10/29  14:47:42  mcooper
  531. X * Added real function UsageString() to
  532. X * handle formating usage option strings.
  533. X * 
  534. X * Revision 1.3  90/10/29  14:17:00  mcooper
  535. X * Allow options to be abbreviated 
  536. X * (for all non StickArg options).
  537. X * 
  538. X * Revision 1.2  90/10/26  15:56:11  mcooper
  539. X * - Fix bug in SepArg code that ate arguments.
  540. X * - Cleanup help message.
  541. X * - Add ArgHidden code.
  542. X * 
  543. X * Revision 1.1  90/10/26  14:42:51  mcooper
  544. X * Initial revision
  545. X * 
  546. X */
  547. X
  548. X/*
  549. X * Functions to parse options.
  550. X */
  551. X
  552. X#include "options.h"
  553. X#ifdef HAS_VARARGS
  554. X#include <varargs.h>
  555. X#endif
  556. X
  557. Xchar *OptionChars = "-+";    /* Default option switching characters */
  558. Xchar *ProgramName = NULL;    /* Name of this program */
  559. Xchar *UsageString();
  560. Xstatic int isopt();
  561. Xstatic int suppress_help_msg = 0;
  562. Xchar *strcat();
  563. X
  564. X/*
  565. X * ParseOptions - Parse options found in argv using "options".
  566. X *          Returns the number of options parsed if there
  567. X *          were no errors.  Returns -1 if an error occurs.
  568. X */
  569. Xint ParseOptions(options, num_options, argc, argv)
  570. X     OptionDescRec *options;
  571. X     int num_options;
  572. X     int argc;
  573. X     char **argv;
  574. X{
  575. X    OptionDescRec *opt;
  576. X    register int x;
  577. X    char *p;
  578. X
  579. X    if (ProgramName == NULL)
  580. X    ProgramName = argv[0];
  581. X
  582. X#ifdef OPTION_DEBUG
  583. X    (void) printf("Option list is:\n");
  584. X    for (x = 0; x < num_options; ++x) {
  585. X    opt = &options[x];
  586. X    (void) printf("%s\n", opt->option);
  587. X    }
  588. X
  589. X    (void) printf("Arguments (%d):", argc);
  590. X    for (x = 0; x < argc; ++x) {
  591. X    (void) printf(" %s", argv[x]);
  592. X    }
  593. X    (void) printf("\n");
  594. X#endif /* OPTION_DEBUG */
  595. X
  596. X    for (x = 1; x < argc; ++x) {
  597. X    if (strcmp(HELPSTR, argv[x]) == 0) {
  598. X        HelpOptions(options, num_options, (char **)NULL);
  599. X        exit(0);
  600. X    }
  601. X
  602. X    opt = FindOption(options, num_options, argv[x]);
  603. X    if (opt == NULL) {
  604. X        if (isopt(argv[x])) { /* this was suppose to be an option */
  605. X        UsageOptions(options, num_options, argv[x]);
  606. X        return(-1);
  607. X        } else { /* must be end of options */
  608. X        break;
  609. X        }
  610. X    }
  611. X
  612. X    if (opt->flags & NoArg) {
  613. X        if (!(*opt->cvtarg)(opt, opt->value, FALSE)) {
  614. X        UsageOptions(options, num_options, opt->option);
  615. X        return(-1);
  616. X        }
  617. X    } else if (opt->flags & IsArg) {
  618. X        if (!(*opt->cvtarg)(opt, opt->option, FALSE)) {
  619. X        UsageOptions(options, num_options, opt->option);
  620. X        return(-1);
  621. X        }
  622. X    } else if ((opt->flags & StickyArg) && (opt->flags & SepArg)) {
  623. X        p = (char *) &argv[x][strlen(opt->option)];
  624. X        if (!*p) {        /*** SepArg ***/
  625. X        if (x + 1 >= argc || isopt(argv[x+1])) {
  626. X            if (opt->value == (caddr_t) NULL) {
  627. X            UserError("%s: Option requires an argument.", argv[x]);
  628. X            UsageOptions(options, num_options, opt->option);
  629. X            return(-1);
  630. X            }
  631. X            p = opt->value;
  632. X        } else {
  633. X            p = argv[++x];
  634. X        }
  635. X        }
  636. X        if (!(*opt->cvtarg)(opt, p, TRUE)) {
  637. X        UsageOptions(options, num_options, opt->option);
  638. X        return(-1);
  639. X        }
  640. X    } else if (opt->flags & StickyArg) {
  641. X        p = (char *) &argv[x][strlen(opt->option)];
  642. X        if (!*p) {
  643. X        if (opt->value == (caddr_t) NULL) {
  644. X            UserError("%s: Option requires an argument.", argv[x]);
  645. X            UsageOptions(options, num_options, opt->option);
  646. X            return(-1);
  647. X        } else {
  648. X            p = opt->value;
  649. X        }
  650. X        }
  651. X        if (!(*opt->cvtarg)(opt, p, TRUE)) {
  652. X        UsageOptions(options, num_options, opt->option);
  653. X        return(-1);
  654. X        }
  655. X    } else if (opt->flags & SepArg) {
  656. X        if (x + 1 >= argc || isopt(argv[x+1])) {
  657. X        if (opt->value == (caddr_t) NULL) {
  658. X            UserError("%s: Option requires an argument.", argv[x]);
  659. X            UsageOptions(options, num_options, opt->option);
  660. X            return(-1);
  661. X        } else {
  662. X            p = opt->value;
  663. X        }
  664. X        } else {
  665. X        p = argv[++x];
  666. X        }
  667. X        if (!(*opt->cvtarg)(opt, p, TRUE)) {
  668. X        UsageOptions(options, num_options, opt->option);
  669. X        return(-1);
  670. X        }
  671. X    } else if (opt->flags & SkipArg) {
  672. X        x += 2;
  673. X    } else if (opt->flags & SkipLine) {
  674. X        return(x);
  675. X    } else if (opt->flags & SkipNArgs) {
  676. X        if (opt->value) {
  677. X        x += atoi(opt->value);
  678. X        } else {
  679. X        UserError("Internal Error: No 'value' set for SkipNArgs.");
  680. X        return(-1);
  681. X        }
  682. X    } else {
  683. X        UserError("Internal Error: Unknown argument type for option '%s'.",
  684. X             opt->option);
  685. X        return(-1);
  686. X    }
  687. X    }
  688. X
  689. X    return(x);
  690. X}
  691. X
  692. X/*
  693. X * FindOption - Find "option" in "options".  Returns NULL if not found.
  694. X */
  695. XOptionDescRec *FindOption(options, num_options, option)
  696. X     OptionDescRec *options;
  697. X     int num_options;
  698. X     char *option;
  699. X{
  700. X    OptionDescRec *opt;
  701. X    register int x;
  702. X
  703. X    for (x = 0; x < num_options; ++x) {
  704. X    opt = &options[x];
  705. X    if (opt->flags & StickyArg) {
  706. X        if (strncmp(option, opt->option, strlen(opt->option)) == 0)
  707. X        return(opt);
  708. X    } else {
  709. X        if (strncmp(option, opt->option, strlen(option)) == 0)
  710. X        return(opt);
  711. X    }
  712. X    }
  713. X
  714. X    return(NULL);
  715. X}
  716. X
  717. X/*
  718. X * isopt - Is "str" an option string?  Compare first char of str against
  719. X *       list of option switch characters.  Returns TRUE if it is an option.
  720. X */
  721. Xstatic int isopt(str)
  722. X     char *str;
  723. X{
  724. X    register char *p;
  725. X
  726. X    for (p = OptionChars; p && *p; *++p) {
  727. X    if (*str == *p) {
  728. X        return(TRUE);
  729. X    }
  730. X    }
  731. X
  732. X    return(FALSE);
  733. X}
  734. X
  735. X/*
  736. X * UsageOptions - Print a usage message based on "options".
  737. X */
  738. Xvoid UsageOptions(options, num_opts, badOption)
  739. X     OptionDescRec *options;
  740. X     int num_opts;
  741. X     char *badOption;
  742. X{
  743. X    OptionDescRec *opt;
  744. X    char *optstr;
  745. X    register int x;
  746. X    int col, len;
  747. X
  748. X    if (badOption) 
  749. X    (void) fprintf (stderr, "%s:  bad command line option \"%s\"\r\n\n",
  750. X            ProgramName, badOption);
  751. X
  752. X    (void) fprintf (stderr, "usage:  %s", ProgramName);
  753. X    col = 8 + strlen(ProgramName);
  754. X    for (x = 0; x < num_opts; x++) {
  755. X    opt = &options[x];
  756. X    if (opt->flags & ArgHidden)
  757. X        continue;
  758. X    optstr = UsageString(opt);
  759. X    len = strlen(optstr) + 3;    /* space [ string ] */
  760. X    if (col + len > 79) {
  761. X        (void) fprintf (stderr, "\r\n   ");  /* 3 spaces */
  762. X        col = 3;
  763. X    }
  764. X    (void) fprintf (stderr, " [%s]", optstr);
  765. X    col += len;
  766. X    }
  767. X
  768. X    if (suppress_help_msg)
  769. X    (void) fprintf(stderr, "\r\n\n");
  770. X    else
  771. X    (void) fprintf(stderr, 
  772. X               "\r\n\nType \"%s %s\" for a full description.\r\n\n",
  773. X               ProgramName, HELPSTR);
  774. X}
  775. X
  776. X/*
  777. X * HelpOptions - Print a nice help/usage message based on options.
  778. X */
  779. Xvoid HelpOptions(options, num_opts, message)
  780. X     OptionDescRec *options;
  781. X     int num_opts;
  782. X     char **message;
  783. X{
  784. X    OptionDescRec *opt;
  785. X    register int x;
  786. X    char **cpp;
  787. X
  788. X    suppress_help_msg = 1;
  789. X    UsageOptions(options, num_opts, (char *)NULL);
  790. X    suppress_help_msg = 0;
  791. X
  792. X    (void) fprintf (stderr, "where options include:\n");
  793. X    for (x = 0; x < num_opts; x++) {
  794. X    opt = &options[x];
  795. X    if (opt->flags & ArgHidden)
  796. X        continue;
  797. X    (void) fprintf (stderr, "    %-28s %s\n", UsageString(opt), 
  798. X         (opt->desc) ? opt->desc : "");
  799. X    if (opt->value && opt->cvtarg != OptBool)
  800. X        (void) fprintf (stderr, "    %-28s [ Default value is %s ]\n", 
  801. X                "", opt->value);
  802. X    }
  803. X
  804. X    if (message) {
  805. X    (void) putc ('\n', stderr);
  806. X    for (cpp = message; *cpp; cpp++) {
  807. X        (void) fputs (*cpp, stderr);
  808. X        (void) putc ('\n', stderr);
  809. X    }
  810. X    (void) putc ('\n', stderr);
  811. X    }
  812. X}
  813. X
  814. X/*
  815. X * UserError - Print a user error.
  816. X */
  817. X#ifdef HAS_VARARGS
  818. Xvoid UserError(va_alist)
  819. X     va_dcl
  820. X{
  821. X    va_list args;
  822. X    char *fmt;
  823. X
  824. X    va_start(args);
  825. X    if (ProgramName)
  826. X    (void) fprintf(stderr, "%s: ", ProgramName);
  827. X    fmt = (char *) va_arg(args, char *);
  828. X    (void) vfprintf(stderr, fmt, args);
  829. X    va_end(args);
  830. X    (void) fprintf(stderr, "\n");
  831. X}
  832. X#else
  833. Xvoid UserError(fmt, a1, a2, a3, a4, a5, a6)
  834. X     char *fmt;
  835. X{
  836. X    if (ProgramName)
  837. X    (void) fprintf(stderr, "%s: ", ProgramName);
  838. X    (void) fprintf(stderr, fmt, a1, a2, a3, a4, a5, a6);
  839. X    (void) fprintf(stderr, "\n");
  840. X}
  841. X#endif
  842. X
  843. XOptBool(opt, value, docopy)
  844. X     OptionDescRec *opt;
  845. X     caddr_t value;
  846. X     int docopy; /*ARGSUSED*/
  847. X{
  848. X    char *vpp;
  849. X
  850. X    *(int *) opt->valp = (int) strtol(value, &vpp, 0);
  851. X    if (*vpp) {
  852. X    UserError("Invalid integer argument for '%s'.", opt->option);
  853. X    return(FALSE);
  854. X    } else {
  855. X    return(TRUE);
  856. X    }
  857. X}
  858. X
  859. XOptInt(opt, value, docopy)
  860. X     OptionDescRec *opt;
  861. X     caddr_t value;
  862. X     int docopy; /*ARGSUSED*/
  863. X{
  864. X    char *vpp;
  865. X
  866. X    *(int *) opt->valp = (int) strtol(value, &vpp, 0);
  867. X    if (*vpp) {
  868. X    UserError("Invalid integer argument for '%s'.", opt->option);
  869. X    return(FALSE);
  870. X    } else {
  871. X    return(TRUE);
  872. X    }
  873. X}
  874. X
  875. XOptShort(opt, value, docopy)
  876. X     OptionDescRec *opt;
  877. X     caddr_t value;
  878. X     int docopy; /*ARGSUSED*/
  879. X{
  880. X    char *vpp;
  881. X
  882. X    *(short *) opt->valp = (short) strtol(value, &vpp, 0);
  883. X    if (*vpp) {
  884. X    UserError("Invalid integer argument for '%s'.", opt->option);
  885. X    return(FALSE);
  886. X    } else {
  887. X    return(TRUE);
  888. X    }
  889. X}
  890. X
  891. XOptLong(opt, value, docopy)
  892. X     OptionDescRec *opt;
  893. X     caddr_t value;
  894. X     int docopy; /*ARGSUSED*/
  895. X{
  896. X    char *vpp;
  897. X
  898. X    *(long *) opt->valp = (long) strtol(value, &vpp, 0);
  899. X    if (*vpp) {
  900. X    UserError("Invalid integer argument for '%s'.", opt->option);
  901. X    return(FALSE);
  902. X    } else {
  903. X    return(TRUE);
  904. X    }
  905. X}
  906. X
  907. XOptStr(opt, value, docopy)
  908. X     OptionDescRec *opt;
  909. X     caddr_t value;
  910. X     int docopy;
  911. X{
  912. X    char *p;
  913. X
  914. X    if (docopy) {
  915. X    if ((p = (char *) malloc((unsigned)strlen(value)+1)) == NULL) {
  916. X        UserError("Cannot malloc memory: %s", SYSERR);
  917. X        return(FALSE);
  918. X    }
  919. X    (void) strcpy(p, value);
  920. X    } else {
  921. X    p = value;
  922. X    }
  923. X
  924. X    *(char **) opt->valp = p;
  925. X
  926. X    return(TRUE);
  927. X}
  928. X
  929. Xstatic char *UsageString(opt)
  930. X     OptionDescRec *opt;
  931. X{
  932. X    static char buf[BUFSIZ], buf2[BUFSIZ];
  933. X
  934. X    (void) sprintf(buf, opt->option);
  935. X    (void) strcpy(buf2, "");
  936. X    if (opt->usage) {
  937. X    (void) sprintf(buf2, "%s%s%s%s",
  938. X               ((opt->flags & StickyArg) && 
  939. X            !((opt->flags & StickyArg) && (opt->flags & SepArg))) 
  940. X               ? "" : " ",
  941. X               (opt->value) ? "[" : "",
  942. X               opt->usage,
  943. X               (opt->value) ? "]" : ""
  944. X               );
  945. X    }
  946. X    (void) strcat(buf, buf2);
  947. X
  948. X    return(buf);
  949. X}
  950. END_OF_FILE
  951.   if test 10901 -ne `wc -c <'options.c'`; then
  952.     echo shar: \"'options.c'\" unpacked with wrong size!
  953.   fi
  954.   # end of 'options.c'
  955. fi
  956. if test -f 'options.h' -a "${1}" != "-c" ; then 
  957.   echo shar: Will not clobber existing file \"'options.h'\"
  958. else
  959.   echo shar: Extracting \"'options.h'\" \(2592 characters\)
  960.   sed "s/^X//" >'options.h' <<'END_OF_FILE'
  961. X/*
  962. X * Copyright (c) 1990 Michael A. Cooper.
  963. X * This software may be freely distributed provided it is not sold for 
  964. X * profit and the author is credited appropriately.
  965. X */
  966. X
  967. X/*
  968. X * $Header: /am/sol/src/common/usc/lib/libgen/RCS/options.h,v 1.7 90/12/15 18:13:30 mcooper Exp $
  969. X *
  970. X * $Log:    options.h,v $
  971. X * Revision 1.7  90/12/15  18:13:30  mcooper
  972. X * Add copywrite notice.
  973. X * 
  974. X * Revision 1.6  90/11/13  15:28:39  mcooper
  975. X * Add OptBool cvtarg routine.
  976. X * 
  977. X * Revision 1.5  90/10/29  19:34:03  mcooper
  978. X * Fixed comment for NoArg.
  979. X * 
  980. X * Revision 1.4  90/10/29  18:48:43  mcooper
  981. X * Cleanup some comments.
  982. X * 
  983. X * Revision 1.3  90/10/29  14:47:29  mcooper
  984. X * UsageString is now a real function.
  985. X * 
  986. X * Revision 1.2  90/10/26  15:55:44  mcooper
  987. X * Add defines for "__" and ArgHidden.
  988. X * 
  989. X * Revision 1.1  90/10/26  14:42:53  mcooper
  990. X * Initial revision
  991. X * 
  992. X */
  993. X
  994. X
  995. X#include <stdio.h>
  996. X#include <sys/types.h>
  997. X#include <sys/errno.h>
  998. X
  999. X#define Num_Opts(o)    (sizeof(o)/sizeof(OptionDescRec))
  1000. X#define HELPSTR        "-help"
  1001. X#define __        (caddr_t)
  1002. X
  1003. X#ifndef SYSERR
  1004. X#define SYSERR        sys_errlist[errno]
  1005. X#endif
  1006. X#ifndef TRUE
  1007. X#define TRUE    1
  1008. X#endif
  1009. X#ifndef FALSE
  1010. X#define FALSE    0
  1011. X#endif
  1012. X
  1013. X/*
  1014. X * Values for OptionDescRec.flags.
  1015. X */
  1016. X#define NoArg        0x001    /* No argument for this option.  Use
  1017. X                   OptionDescRec.value. */
  1018. X#define IsArg        0x002    /* Value is the option string itself */
  1019. X#define SepArg        0x004    /* Value is in next argument in argv */
  1020. X#define StickyArg    0x008    /* Value is characters immediately following 
  1021. X                   option */
  1022. X#define SkipArg        0x010    /* Ignore this option and the next argument in 
  1023. X                   argv */
  1024. X#define SkipLine    0x020    /* Ignore this option and the rest of argv */
  1025. X#define SkipNArgs    0x040    /* Ignore this option and the next 
  1026. X                   OptionDescRes.value arguments in argv */
  1027. X#define ArgHidden    0x080    /* Don't show in usage or help messages */
  1028. X
  1029. X/*
  1030. X * Option description record.
  1031. X */
  1032. Xtypedef struct {
  1033. X    char    *option;        /* Option string in argv        */
  1034. X    int         flags;            /* Flag bits                */
  1035. X    int        (*cvtarg)();        /* Function to convert argument     */
  1036. X    caddr_t     valp;            /* Variable to set            */
  1037. X    caddr_t     value;            /* Default value to provide        */
  1038. X    char    *usage;            /* Usage message            */
  1039. X    char    *desc;            /* Description message            */
  1040. X} OptionDescRec, *OptionDescList;
  1041. X
  1042. Xvoid UsageOptions();
  1043. Xvoid HelpOptions();
  1044. Xvoid UserError();
  1045. Xint ParseOptions();
  1046. XOptionDescRec *FindOption();
  1047. X
  1048. Xint OptBool();
  1049. Xint OptInt();
  1050. Xint OptLong();
  1051. Xint OptShort();
  1052. Xint OptStr();
  1053. X
  1054. Xextern char *OptionChars;
  1055. Xextern int errno;
  1056. Xextern char *sys_errlist[];
  1057. Xextern long strtol();
  1058. Xextern char *malloc();
  1059. Xextern char *strcpy();
  1060. END_OF_FILE
  1061.   if test 2592 -ne `wc -c <'options.h'`; then
  1062.     echo shar: \"'options.h'\" unpacked with wrong size!
  1063.   fi
  1064.   # end of 'options.h'
  1065. fi
  1066. if test -f 'qterm.c' -a "${1}" != "-c" ; then 
  1067.   echo shar: Will not clobber existing file \"'qterm.c'\"
  1068. else
  1069.   echo shar: Extracting \"'qterm.c'\" \(24777 characters\)
  1070.   sed "s/^X//" >'qterm.c' <<'END_OF_FILE'
  1071. X#ifndef lint
  1072. Xstatic char *RCSid = "$Header: /src/common/usc/bin/qterm/RCS/qterm.c,v 5.4 1991/03/21 02:09:40 mcooper Exp $";
  1073. X#endif
  1074. X
  1075. X/*
  1076. X * Copyright (c) 1990 Michael A. Cooper.
  1077. X * This software may be freely distributed provided it is not sold for 
  1078. X * profit and the author is credited appropriately.
  1079. X */
  1080. X
  1081. X/*
  1082. X *------------------------------------------------------------------
  1083. X *
  1084. X * $Source: /src/common/usc/bin/qterm/RCS/qterm.c,v $
  1085. X * $Revision: 5.4 $
  1086. X * $Date: 1991/03/21 02:09:40 $
  1087. X * $State: Exp $
  1088. X * $Author: mcooper $
  1089. X * $Locker:  $
  1090. X *
  1091. X *------------------------------------------------------------------
  1092. X *
  1093. X * Michael A. Cooper
  1094. X * Research and Development Group
  1095. X * University Computing Services 
  1096. X * University of Southern California
  1097. X * (mcooper@usc.edu)
  1098. X *
  1099. X *------------------------------------------------------------------
  1100. X *
  1101. X * $Log: qterm.c,v $
  1102. X * Revision 5.4  1991/03/21  02:09:40  mcooper
  1103. X * Fix memory buffer problem with some C
  1104. X * compilers.  (tp@vtold.vtol.fi)
  1105. X *
  1106. X * Revision 5.3  1991/03/16  05:36:30  mcooper
  1107. X * Fix casting of (char) NULL problem.
  1108. X *
  1109. X * Revision 5.2  1991/03/12  00:46:24  mcooper
  1110. X * Change CMASK to CHAR_CMASK to avoid conflict
  1111. X * under AIX 3.1.
  1112. X *
  1113. X * Revision 5.1  1991/02/20  02:23:33  mcooper
  1114. X * Cleanup #ifdef USG5 as part of port
  1115. X * to UTS 2.1 (System V.3).
  1116. X *
  1117. X * Revision 5.0  1990/12/15  18:30:41  mcooper
  1118. X * Version 5.
  1119. X *
  1120. X * Revision 4.13  90/12/15  18:14:23  mcooper
  1121. X * Add copywrite.
  1122. X * 
  1123. X * Revision 4.12  90/11/13  16:00:03  mcooper
  1124. X * Convert OptInt's to OptBool's where needed.
  1125. X * 
  1126. X * Revision 4.11  90/11/13  15:38:28  mcooper
  1127. X * Make OLD_SepArg include both
  1128. X * SepArg and StickyArg.
  1129. X * 
  1130. X * Revision 4.10  90/11/08  15:41:08  mcooper
  1131. X * Make sure qt_fullname is not 0 length.
  1132. X * 
  1133. X * Revision 4.9  90/11/08  13:02:06  mcooper
  1134. X * Fix bug that closes the tty when an error
  1135. X * occurs during command line parsing.
  1136. X * 
  1137. X * Revision 4.8  90/11/06  13:19:40  mcooper
  1138. X * Changed command line options to new 
  1139. X * longer names.
  1140. X * 
  1141. X * Revision 4.7  90/11/05  17:09:30  mcooper
  1142. X * Update option help messages and option names
  1143. X * to be more mnemonic.
  1144. X * 
  1145. X * Revision 4.6  90/11/05  16:44:35  mcooper
  1146. X * - Converted to use new ParseOptions() for
  1147. X *   command line parsing.
  1148. X * - Major de-linting.
  1149. X * - Convert dprintf() to use varargs (if
  1150. X *   HAS_VARARGS is defined).
  1151. X * - Lots of misc. cleanup.
  1152. X * 
  1153. X * Revision 4.5  89/10/20  22:50:49  mcooper
  1154. X * Changed code indention to current local
  1155. X * standard of 4.  (This should also mess up
  1156. X * everybody trying to do diff's from older versions!)
  1157. X * 
  1158. X * Revision 4.4  89/10/20  14:03:48  mcooper
  1159. X * Fixed command line parsing of "-f -q".
  1160. X * 
  1161. X * Revision 4.3  88/06/16  19:43:46  mcooper
  1162. X * - Added -T flag to wait until timeout when
  1163. X *   listening for response string.  This solves
  1164. X *   problem when the first entry in a table
  1165. X *   doesn't have a response string with a
  1166. X *   common ending character to look for.
  1167. X * - Added -I flag for "intense" query mode.
  1168. X * - Cleaned up debugging a bit.
  1169. X * 
  1170. X * Revision 4.2  88/06/08  15:30:53  mcooper
  1171. X * Cleanup pass including removing
  1172. X * extraneous debugging messages.
  1173. X * 
  1174. X * Revision 4.1  88/04/25  13:24:38  mcooper
  1175. X * Added -S option to print send and recieve
  1176. X * strings as they are sent and recieved as
  1177. X * suggested by David W. Sanderson
  1178. X * (dws@attunix.att.com).
  1179. X * 
  1180. X * Revision 4.0  88/03/08  19:30:59  mcooper
  1181. X * Version 4.
  1182. X * 
  1183. X * Revision 3.7  88/03/08  19:28:32  mcooper
  1184. X * Major rewrite.
  1185. X * 
  1186. X * Revision 3.6  88/03/08  15:31:35  mcooper
  1187. X * General cleanup time.
  1188. X * 
  1189. X * Revision 3.5  88/03/08  13:59:39  mcooper
  1190. X * - Catch signals and fix terminal modes.
  1191. X * - Don't allow alarm times of 0.
  1192. X * - Support for HP-UX machines and cleaner
  1193. X *   listen() code from Zenon Fortuna, 
  1194. X *   HP-UX Support, Hewlett-Packard Vienna.
  1195. X * 
  1196. X * Revision 3.4  87/10/07  15:16:17  mcooper
  1197. X * - Beautify code a bit.
  1198. X * - Add -w <N> option to set the wait time.
  1199. X * 
  1200. X * Revision 3.3  87/08/24  19:25:32  mcooper
  1201. X * The following based on code from Frank Crawford 
  1202. X * <frank@teti.qhtours.OZ>:
  1203. X * - Use $TERM as output string when the terminal
  1204. X *   type is not known instead of "dumb".
  1205. X * - Regular Expressions are now supported.  RE are
  1206. X *   started with a leading `\'.
  1207. X * - Octal values may now be used in send/recieve strings.
  1208. X * 
  1209. X * Revision 3.1  87/08/03  15:21:07  mcooper
  1210. X * As pointed out by Scott H. Robinson <shr@cetus.ece.cmu.edu>,
  1211. X * the -F switch does work.  Problem was that it never read
  1212. X * in the ~/.qterm file.
  1213. X * 
  1214. X * Revision 3.0  87/06/30  19:07:59  mcooper
  1215. X * Release of version 3.
  1216. X * 
  1217. X * Revision 2.4  87/04/29  19:28:35  mcooper
  1218. X * In readtabfile() we now do special
  1219. X * things when opening "file" fails
  1220. X * depending on the bequiet flag.
  1221. X * 
  1222. X * Revision 2.3  87/04/29  13:11:37  mcooper
  1223. X * - No more "internal" table.  The master
  1224. X *   table is read from a file (TABFILE).
  1225. X *   This makes ~/.qterm stuff much cleaner.
  1226. X * - Error handling for qtermtab files is
  1227. X *   much more informative now.
  1228. X * - More things I can't remember.
  1229. X * 
  1230. X * Revision 2.2  87/03/05  21:01:28  mcooper
  1231. X * Fixed system V compiler problem.
  1232. X * 
  1233. X * Revision 2.1  87/03/01  19:43:22  mcooper
  1234. X * Be more intelligent about the size of 
  1235. X * the default terminal table.
  1236. X * 
  1237. X * Revision 2.0  87/03/01  19:20:00  mcooper
  1238. X * General cleanup.
  1239. X * 
  1240. X *------------------------------------------------------------------
  1241. X */
  1242. X
  1243. X
  1244. X/*
  1245. X * qterm - Query Terminal
  1246. X *
  1247. X * qterm is used to query a terminal to determine the name of the terminal.
  1248. X * This is done by sending a fairly universal string "\33Z" to the terminal,
  1249. X * reading in a response, and comparing it against a master table of responses
  1250. X * and names.  The "name" printed to standard output should be one found in
  1251. X * the termcap(5) database.
  1252. X *
  1253. X * Putting a line in your ".login" file such as:
  1254. X *
  1255. X *    setenv TERM `qterm`
  1256. X *
  1257. X * or the following lines in your ".profile" file:
  1258. X *
  1259. X *    TERM=`qterm`
  1260. X *    export TERM
  1261. X *
  1262. X * will set your terminal type automagically.
  1263. X * 
  1264. X * If you add a terminal to the master table, please also send me a copy
  1265. X * so that I may put it into my version.
  1266. X *
  1267. X * Michael Cooper
  1268. X * Internet:     mcooper@usc.edu
  1269. X * UUCP:     ...!rutgers!usc!mcooper
  1270. X * BITNET:    mcooper@gamera
  1271. X */
  1272. X
  1273. X#include <stdio.h>
  1274. X#include <ctype.h>
  1275. X#include <pwd.h>
  1276. X#include <signal.h>
  1277. X#include <sys/ioctl.h>
  1278. X#include <setjmp.h>
  1279. X#ifdef USG5
  1280. X# include <termio.h>
  1281. X#else /*USG5*/
  1282. X# include <sys/file.h>
  1283. X# include <sgtty.h>
  1284. X#endif /*USG5*/
  1285. X#include "qterm.h"
  1286. X#include "options.h"
  1287. X#ifdef HAS_VARARGS
  1288. X#include <varargs.h>
  1289. X#endif /*HAS_VARARGS*/
  1290. X
  1291. X#ifdef USG5
  1292. Xstruct termio _ntty, _otty;
  1293. X#else
  1294. Xstruct sgttyb _tty;
  1295. X#endif
  1296. Xint _tty_ch = 2;
  1297. Xchar recvbuf[SIZE];
  1298. Xchar *progname;
  1299. Xchar *termfile = NULL;
  1300. X
  1301. Xint debug = FALSE;        /* Debug mode */
  1302. Xint use_alt_str = FALSE;    /* Alternate string */
  1303. Xint towait = FALSE;        /* Time out wait flag */
  1304. Xint always_send = FALSE;    /* Intense query mode */
  1305. Xint longname = FALSE;        /* Print long terminal name */
  1306. Xint sent_chars = FALSE;        /* Print strings sent from the terminal */
  1307. Xint watch_chars = FALSE;    /* Watch strings as they are sent and recv. */
  1308. Xint quiet = FALSE;        /* Quiet mode */
  1309. Xint do_usrtabfile = FALSE;    /* Use user's own .qtermtab file */
  1310. Xint do_systabfile = TRUE;    /* Use the system's qterm tab file */
  1311. Xint almwait = WAIT;        /* Wait (timeout) interval */
  1312. X
  1313. X/*
  1314. X * Old options should not be visable in help and usage messages.
  1315. X */
  1316. X#ifdef OPT_COMPAT
  1317. X#define OLD_NoArg    NoArg|ArgHidden
  1318. X#define OLD_SepArg    SepArg|StickyArg|ArgHidden
  1319. X#define fFLAG         "-f"
  1320. X#define FFLAG        "-F"
  1321. X#endif
  1322. X
  1323. X/*
  1324. X * Command line options table.
  1325. X */
  1326. XOptionDescRec opts[] = {
  1327. X#ifdef OPT_COMPAT
  1328. X    {"-a",     OLD_NoArg,    OptInt,    (caddr_t) &use_alt_str,        "1",
  1329. X     (char *)NULL,    "Use alternate query string"},
  1330. X    {"-s",    OLD_NoArg,    OptInt,    (caddr_t) &sent_chars,        "1",
  1331. X     (char *)NULL,    "Display the characters the terminal sent"},
  1332. X    {"-t", ArgHidden|OLD_NoArg,    OptInt,    (caddr_t) &sent_chars,        "1",
  1333. X     (char *)NULL,    "Display the characters the terminal sent"},
  1334. X    {"-I",    OLD_NoArg,    OptInt,    (caddr_t) &always_send,        "1",
  1335. X     (char *)NULL,    "Always send the terminal query string"},
  1336. X    {"-T",    OLD_NoArg,    OptInt,    (caddr_t) &towait,        "1",
  1337. X     (char *)NULL,    "Enable time out wait"},
  1338. X    {"-S",    OLD_NoArg,    OptInt,    (caddr_t) &watch_chars,        "1",
  1339. X     (char *)NULL,    "Print strings as they are sent and received"},
  1340. X    {"-q",    OLD_NoArg,    OptInt,    (caddr_t) &quiet,        "1",
  1341. X     (char *)NULL,    "Enable quite mode"},
  1342. X    {"-f",    OLD_SepArg,    OptStr,    (caddr_t) &termfile,  fFLAG,
  1343. X     "<tabfile>",  "Try <tabfile>, then ~/.qtermtab, then system tabfile"},
  1344. X    {"-F",    OLD_SepArg,    OptStr,    (caddr_t) &termfile,  FFLAG,
  1345. X     "<tabfile>",    "Try <tabfile>, then ~/.qtermtab"},
  1346. X    {"-l",    OLD_NoArg,    OptInt,    (caddr_t) &longname,        "1",
  1347. X     (char *)NULL,    "Output only the long (verbose) terminal name"},
  1348. X    {"-d",     OLD_NoArg,    OptInt,    (caddr_t) &debug,        "1",
  1349. X     (char *)NULL,    "Enable debug mode"},
  1350. X    {"-w",    OLD_SepArg,    OptInt,    (caddr_t) &almwait,        __ NULL,
  1351. X     "<interval>",    "Wait (timeout) period (in seconds)"},
  1352. X#endif /*OPT_COMPAT*/
  1353. X    {"+alt",     NoArg,        OptBool, (caddr_t) &use_alt_str,    "1",
  1354. X     (char *)NULL,    "Use alternate query string"},
  1355. X    {"-alt",     NoArg,        OptBool, (caddr_t) &use_alt_str,    "0",
  1356. X     (char *)NULL,    "Don't use alternate query string"},
  1357. X    {"+always",    NoArg,        OptBool, (caddr_t) &always_send,    "1",
  1358. X     (char *)NULL,    "Always send the terminal query string"},
  1359. X    {"-always",    NoArg,        OptBool, (caddr_t) &always_send,    "0",
  1360. X     (char *)NULL,    "Don't always send the terminal query string"},
  1361. X    {"-file",    SepArg,        OptStr,    (caddr_t) &termfile,          __ NULL,
  1362. X     "<tabfile>",   "Use <tabfile> to query terminal"},
  1363. X    {"+longname",NoArg,        OptBool, (caddr_t) &longname,        "1",
  1364. X     (char *)NULL,    "Output only the long (verbose) terminal name"},
  1365. X    {"-longname",NoArg,        OptBool, (caddr_t) &longname,        "0",
  1366. X     (char *)NULL,    "Don't output the long (verbose) terminal name"},
  1367. X    {"+quiet",    NoArg,        OptBool, (caddr_t) &quiet,        "1",
  1368. X     (char *)NULL,    "Enable quiet mode"},
  1369. X    {"-quiet",    NoArg,        OptBool, (caddr_t) &quiet,        "0",
  1370. X     (char *)NULL,    "Disable quiet mode"},
  1371. X    {"+sent",    NoArg,        OptBool, (caddr_t) &sent_chars,        "1",
  1372. X     (char *)NULL,    "Display the characters the terminal sent"},
  1373. X    {"-sent",    NoArg,        OptBool, (caddr_t) &sent_chars,        "0",
  1374. X     (char *)NULL,    "Don't display the characters the terminal sent"},
  1375. X    {"+timeout",NoArg,        OptBool, (caddr_t) &towait,        "1",
  1376. X     (char *)NULL,    "Enable time out wait"},
  1377. X    {"-timeout",NoArg,        OptBool, (caddr_t) &towait,        "0",
  1378. X     (char *)NULL,    "Disable time out wait"},
  1379. X    {"+usrtab",    NoArg,        OptBool, (caddr_t) &do_usrtabfile,    "1",
  1380. X     (char *)NULL,    "Enable using ~/.qtermtab"},
  1381. X    {"-usrtab",    NoArg,        OptBool, (caddr_t) &do_usrtabfile,    "0",
  1382. X     (char *)NULL,    "Disable using ~/.qtermtab"},
  1383. X    {"-wait",    SepArg,        OptInt,    (caddr_t) &almwait,        __ NULL,
  1384. X     "<interval>",    "Wait (timeout) period (in seconds)"},
  1385. X    {"+watch",    NoArg,        OptBool, (caddr_t) &watch_chars,    "1",
  1386. X     (char *)NULL,    "Watch the characters sent and recieved"},
  1387. X    {"-watch",    NoArg,        OptBool, (caddr_t) &watch_chars,    "0",
  1388. X     (char *)NULL,    "Don't watch the characters sent and recieved"},
  1389. X    {"+systab",    NoArg,        OptBool, (caddr_t) &do_usrtabfile,    "1",
  1390. X     (char *)NULL,    "Enable using system qtermtab file"},
  1391. X    {"-systab",    NoArg,        OptBool, (caddr_t) &do_systabfile,    "0",
  1392. X     (char *)NULL,    "Disable using system qtermtab file"},
  1393. X    {"-debug", ArgHidden|NoArg,    OptInt,    (caddr_t) &debug,        "1",
  1394. X     (char *)NULL,    "Enable debug mode"},
  1395. X};
  1396. X
  1397. XFILE *fopen();
  1398. Xchar *decode();
  1399. Xchar *getenv();
  1400. Xchar *malloc();
  1401. Xchar *re_comp();
  1402. Xchar *strcat();
  1403. Xchar *xmalloc();
  1404. Xint alarm();
  1405. Xint found = FALSE;
  1406. Xint modes_set = FALSE;
  1407. Xjmp_buf env;
  1408. Xstruct termtable *compare();
  1409. Xstruct passwd *getpwuid();
  1410. Xvoid catch();
  1411. Xvoid done();
  1412. Xvoid dprintf();
  1413. Xvoid exit();
  1414. Xvoid myperror();
  1415. Xvoid mktable();
  1416. Xvoid notrecognized();
  1417. Xvoid proctab();
  1418. Xvoid wakeup();
  1419. X#ifdef USG5
  1420. Xchar *regcmp();
  1421. X#endif /* USG5 */
  1422. X
  1423. Xmain(argc, argv)
  1424. X     int argc;
  1425. X     char **argv;
  1426. X{
  1427. X    config(argc, argv);
  1428. X    setmodes();
  1429. X    mktable();
  1430. X    proctab((struct termtable *)NULL);
  1431. X    resetmodes();
  1432. X    
  1433. X    if (!found) {
  1434. X    notrecognized();
  1435. X    }
  1436. X
  1437. X    exit(0);
  1438. X}
  1439. X
  1440. X/*
  1441. X * Config() - Perform configuration operations.
  1442. X */
  1443. Xconfig(argc, argv)
  1444. X     int argc;
  1445. X     char **argv;
  1446. X{
  1447. X    progname = argv[0];
  1448. X
  1449. X    /*
  1450. X     * Parse command line args
  1451. X     */
  1452. X    if (ParseOptions(opts, Num_Opts(opts), argc, argv) < 0) {
  1453. X    done(1);
  1454. X    /*NOTREACHED*/
  1455. X    }
  1456. X
  1457. X    /*
  1458. X     * Check results of command line parsing and perform any
  1459. X     * needed post processing.
  1460. X     */
  1461. X
  1462. X    if (longname)
  1463. X    quiet = TRUE;
  1464. X
  1465. X    if (almwait == 0) {
  1466. X    (void) fprintf(stderr, 
  1467. X              "%s: Alarm (wait) time must be greater than 0.\n",
  1468. X               progname);
  1469. X    done(1);
  1470. X    /*NOTREACHED*/
  1471. X    }
  1472. X
  1473. X#ifdef OPT_COMPAT
  1474. X    /*
  1475. X     * Kludgy stuff to be backwards compatable for command line options.
  1476. X     */
  1477. X    if (termfile) {
  1478. X    if (strcmp(termfile, fFLAG) == 0) {
  1479. X        do_usrtabfile = TRUE;
  1480. X        do_systabfile = TRUE;
  1481. X        termfile = NULL;
  1482. X    } else if (strcmp(termfile, FFLAG) == 0) {
  1483. X        do_usrtabfile = TRUE;
  1484. X        do_systabfile = FALSE;
  1485. X        termfile = NULL;
  1486. X    }
  1487. X    }
  1488. X#endif /*OPT_COMPAT*/
  1489. X
  1490. X    dprintf("[ %s debug mode enabled ]\n\n", progname);
  1491. X}
  1492. X
  1493. X/*
  1494. X * Set signal catches and terminal modes
  1495. X */
  1496. Xsetmodes()
  1497. X{
  1498. X    if (!isatty(0)) {
  1499. X    (void) fprintf(stderr, "%s: Not a tty.\n", progname);
  1500. X    done(0);
  1501. X    /*NOTREACHED*/
  1502. X    }
  1503. X    
  1504. X    /*
  1505. X     * Set output buffers
  1506. X     */
  1507. X    setbuf(stdout, (char *)0);
  1508. X    if (debug)
  1509. X    setbuf(stderr, (char *)0);
  1510. X    
  1511. X    /*
  1512. X     * Cleanup terminal modes & such if we are killed
  1513. X     */
  1514. X    (void) signal(SIGINT, catch);
  1515. X    (void) signal(SIGHUP, catch);
  1516. X    (void) signal(SIGTERM, catch);
  1517. X    
  1518. X    /*
  1519. X     * Set terminal modes
  1520. X     */
  1521. X#ifdef USG5
  1522. X    if (ioctl(_tty_ch, TCGETA, &_otty) < 0)
  1523. X#else
  1524. X    if (ioctl(_tty_ch, TIOCGETP, &_tty) < 0)
  1525. X#endif /* USG5 */
  1526. X    {
  1527. X    myperror("gtty");
  1528. X    done(1);
  1529. X    /*NOTREACHED*/
  1530. X    }
  1531. X#ifdef USG5
  1532. X    _ntty = _otty;
  1533. X#endif /* USG5 */
  1534. X
  1535. X    if (crmode() < 0) {
  1536. X    myperror("crmode");
  1537. X    done(1);
  1538. X    /*NOTREACHED*/
  1539. X    }
  1540. X    
  1541. X    if (noecho() < 0) {
  1542. X    myperror("noecho");
  1543. X    done(1);
  1544. X    /*NOTREACHED*/
  1545. X    }
  1546. X    modes_set = TRUE;
  1547. X}
  1548. X
  1549. X/*
  1550. X * Reset terminal modes
  1551. X */
  1552. Xresetmodes()
  1553. X{
  1554. X    if (modes_set) {
  1555. X    (void) nocrmode();
  1556. X    (void) echo();
  1557. X    }
  1558. X}
  1559. X
  1560. X/*
  1561. X * Print info about terminal structure t.
  1562. X */
  1563. Xprinfo(t, what)
  1564. X     struct termtable *t;
  1565. X     int what;
  1566. X{
  1567. X    int len = 0;
  1568. X    int st = FALSE;
  1569. X    
  1570. X    if (t && t->qt_termname && (recvbuf[0] != (char) NULL)) {
  1571. X    if (debug || sent_chars) {
  1572. X        len = strlen(recvbuf);
  1573. X        (void) fprintf(stderr, "%s received %d character%s:", 
  1574. X               progname, len, (len == 1) ? "" : "s");
  1575. X        (void) fprintf(stderr, " %s\n", decode(recvbuf));
  1576. X    }
  1577. X    
  1578. X    if (!quiet) {
  1579. X        (void) fprintf(stderr, "Terminal recognized as %s", 
  1580. X               t->qt_termname);
  1581. X        if (t->qt_fullname && t->qt_fullname[0])
  1582. X        (void) fprintf(stderr, " (%s)\n", t->qt_fullname);
  1583. X        else
  1584. X        (void) fprintf(stderr, "\n");
  1585. X    }
  1586. X    
  1587. X    if (longname) {
  1588. X        if (t->qt_fullname && t->qt_fullname[0])
  1589. X        (void) printf("%s\n", t->qt_fullname);
  1590. X        else
  1591. X        (void) fprintf(stderr, "%s: No full terminal name for %s.\n",
  1592. X                   progname, t->qt_termname);
  1593. X    } else {
  1594. X        (void) printf("%s\n", t->qt_termname);
  1595. X    }
  1596. X    
  1597. X    found = TRUE;
  1598. X    done(0);
  1599. X    /*NOTREACHED*/
  1600. X    } else {
  1601. X    found = FALSE;
  1602. X    
  1603. X    if (what) {
  1604. X        notrecognized();
  1605. X        done(1);
  1606. X        /*NOTREACHED*/
  1607. X    }
  1608. X    }
  1609. X    
  1610. X    return(st);
  1611. X}
  1612. X
  1613. X/*
  1614. X * compare - actually compare what we received against the table.
  1615. X */
  1616. Xstruct termtable *compare(str)
  1617. X     char *str;
  1618. X{
  1619. X#ifdef USG5
  1620. X    register char *reexp;
  1621. X#endif /* USG5 */
  1622. X    register struct termtable *t;
  1623. X    char buf[BUFSIZ];
  1624. X
  1625. X    dprintf("compare %s\n", (str && str[0]) ? decode(str) : "nothing");
  1626. X    (void) alarm((unsigned)0);
  1627. X    
  1628. X    if (strlen(str) == 0)
  1629. X    return(NULL);
  1630. X    
  1631. X    for (t = termtab; t != NULL; t = t->nxt) {
  1632. X    dprintf("  with %s ", decode(t->qt_recvstr));
  1633. X    (void) sprintf(buf, "^%s$", t->qt_recvstr);
  1634. X    
  1635. X#ifdef USG5
  1636. X    if ((reexp = regcmp(buf, NULL)) == NULL) {
  1637. X#else
  1638. X    if (re_comp((char *)buf) != NULL) {
  1639. X#endif /* USG5 */
  1640. X        (void) fprintf(stderr, "%s: bad regular expression: \"%s\"\n", 
  1641. X               progname, t->qt_recvstr);
  1642. X        done(1);
  1643. X        /*NOTREACHED*/
  1644. X    }
  1645. X
  1646. X#ifdef USG5
  1647. X    if (regex(reexp, str) != NULL) {
  1648. X#else
  1649. X    if (re_exec(str) == 1) {
  1650. X#endif /* USG5 */
  1651. X        found = TRUE;
  1652. X        dprintf("\tOK\n");
  1653. X        return(t);
  1654. X    }
  1655. X
  1656. X    dprintf("\tNOPE\n");
  1657. X#ifdef USG5
  1658. X    (void) free(reexp);
  1659. X#endif /* USG5 */
  1660. X    }
  1661. X    found = FALSE;
  1662. X
  1663. X    return(NULL);
  1664. X}
  1665. X
  1666. X/*
  1667. X * getch - read in a character at a time.
  1668. X */
  1669. Xgetch()
  1670. X{
  1671. X    char c;
  1672. X    
  1673. X    (void) read(0, &c, 1);
  1674. X    
  1675. X    return(c & CHAR_MASK);
  1676. X}
  1677. X
  1678. X/*
  1679. X * decode - print str in a readable fashion
  1680. X */
  1681. Xchar *decode(str)
  1682. X     char *str;
  1683. X{
  1684. X    register int len;
  1685. X    static char buf[BUFSIZ];
  1686. X    char tmp[10];
  1687. X    
  1688. X    if (!str)
  1689. X      return("(null)");
  1690. X    
  1691. X    (void) strcpy(buf, "");
  1692. X    while (*str) {
  1693. X    if (*str == ESC) {
  1694. X        (void) strcat(buf, "<esc> ");
  1695. X    } else if ((*str <= 33) || (*str >= 127)) {
  1696. X        (void) sprintf(tmp,"\\%#o ", (unsigned) *str);
  1697. X        (void) strcat(buf, tmp);
  1698. X    } else {
  1699. X        (void) sprintf(tmp,"%c ", *str);
  1700. X        (void) strcat(buf, tmp);
  1701. X    }
  1702. X    ++str;
  1703. X    }
  1704. X    
  1705. X    len = strlen(buf);
  1706. X    if (len && buf[len - 1] == ' ') {
  1707. X    buf[len - 1] = (char) NULL;
  1708. X    }
  1709. X    
  1710. X    return(buf);
  1711. X}
  1712. X
  1713. X/*
  1714. X * Make a termtab table
  1715. X */
  1716. Xvoid mktable()
  1717. X{
  1718. X    char file[BUFSIZ];
  1719. X    struct passwd *pwd;
  1720. X    char *home;
  1721. X
  1722. X    dprintf("[ initilizing term table... ]\n");
  1723. X    
  1724. X    if (termfile != NULL) {
  1725. X    (void) readtabfile(termfile, FALSE);
  1726. X    }
  1727. X
  1728. X    if (do_usrtabfile) {
  1729. X    /*
  1730. X     * Try to read the user's own table
  1731. X     */
  1732. X    if ((home = getenv("HOME")) == NULL) {
  1733. X        if ((pwd = getpwuid(getuid())) == NULL) {
  1734. X        (void) fprintf(stderr, 
  1735. X                   "%s: Cannot find user info for uid %d.\n",
  1736. X                   progname, getuid());
  1737. X        done(1);
  1738. X        /*NOTREACHED*/
  1739. X        }
  1740. X        home = pwd->pw_dir;
  1741. X    }
  1742. X
  1743. X    (void) sprintf(file, "%s/%s", home, USRFILE);
  1744. X    if (readtabfile(file, TRUE) < 0) {
  1745. X        (void) sprintf(file, "%s/%s", home, OLDUSRFILE);
  1746. X        (void) readtabfile(file, TRUE);
  1747. X    }
  1748. X    }
  1749. X    
  1750. X    if (do_systabfile)
  1751. X    (void) readtabfile(TABFILE, FALSE);
  1752. X    
  1753. X    dprintf("[ mktable done ]\n");
  1754. X}
  1755. X
  1756. Xint readtabfile(file, bequiet)
  1757. X     char *file;
  1758. X     int bequiet;
  1759. X{
  1760. X    static int line = 0;
  1761. X    char lbuf[4][BUFSIZ];
  1762. X    char buf[BUFSIZ];
  1763. X    FILE *fd;
  1764. X    char *p, *fixctl();
  1765. X    char *errmsg = NULL;
  1766. X    struct termtable *t;
  1767. X    
  1768. X    if ((fd = fopen(file, "r")) == NULL) {
  1769. X    if (bequiet) {
  1770. X        dprintf("[ tab file '%s' can not read ]\n", file);
  1771. X        return(-1);
  1772. X    }
  1773. X    myperror(file);
  1774. X    done(1);
  1775. X    /*NOTREACHED*/
  1776. X    }
  1777. X
  1778. X    dprintf("[ Read tab file '%s' ]\n", file);
  1779. X
  1780. X    line = 0;
  1781. X    while (fgets(buf, sizeof(buf), fd)) {
  1782. X    ++line;
  1783. X    
  1784. X    if (buf[0] == '#' || buf[0] == '\n')
  1785. X        continue;
  1786. X    
  1787. X    lbuf[0][0] = lbuf[1][0] = lbuf[2][0] = lbuf[3][0] = (char) NULL;
  1788. X    
  1789. X    (void) sscanf(buf, "%s%s%s\t%[^\n]", 
  1790. X              lbuf[0], lbuf[1], lbuf[2], lbuf[3]);
  1791. X    
  1792. X    if (lbuf[0][0] == (char) NULL)
  1793. X        continue;
  1794. X    
  1795. X    if (lbuf[1][0] == (char) NULL)
  1796. X        errmsg = "receive string";
  1797. X    
  1798. X    if (lbuf[2][0] == (char) NULL)
  1799. X        errmsg = "terminal name";
  1800. X    
  1801. X    if (errmsg) {
  1802. X        (void) fprintf(stderr, "%s: Line %d of %s: Error parsing %s.\n", 
  1803. X               progname, line, file, errmsg);
  1804. X        done(1);
  1805. X        /*NOTREACHED*/
  1806. X    }
  1807. X    
  1808. X    t = (struct termtable *) xmalloc(sizeof(struct termtable));
  1809. X    
  1810. X    if (use_alt_str)
  1811. X        p = fixctl(ALTSEND, 0);
  1812. X    else
  1813. X        p = fixctl(lbuf[0], 0);
  1814. X    
  1815. X    t->qt_sendstr = (char *) xmalloc(strlen(p)+1);
  1816. X    (void) strcpy(t->qt_sendstr, p);
  1817. X    
  1818. X    p = fixctl(lbuf[1], 1);
  1819. X    t->qt_recvstr = (char *) xmalloc(strlen(p)+1);
  1820. X    (void) strcpy(t->qt_recvstr, p);
  1821. X    
  1822. X    t->qt_termname = (char *) xmalloc(strlen(lbuf[2])+1);
  1823. X    (void) strcpy(t->qt_termname, lbuf[2]);
  1824. X    
  1825. X    t->qt_fullname = (char *) xmalloc(strlen(lbuf[3])+1);
  1826. X    (void) strcpy(t->qt_fullname, lbuf[3]);
  1827. X    
  1828. X    dprintf("\n  Send String = %s\n", decode(t->qt_sendstr));
  1829. X    dprintf("Expect String = %s\n", decode(t->qt_recvstr));
  1830. X    dprintf("     Terminal = '%s'\n", t->qt_termname);
  1831. X    dprintf("    Full Name = '%s'\n", t->qt_fullname);
  1832. X    
  1833. X    (void) addterm(t);
  1834. X    }
  1835. X    
  1836. X    return(0);
  1837. X}
  1838. X
  1839. X/*
  1840. X * Add termtab (n) entry to main termtab.
  1841. X */
  1842. Xint addterm(n)
  1843. X     struct termtable *n;
  1844. X{
  1845. X    register struct termtable *t;
  1846. X    
  1847. X    if (!n)
  1848. X      return(-1);
  1849. X    
  1850. X    n->nxt = NULL;
  1851. X    
  1852. X    if (termtab == NULL) {
  1853. X    termtab = n;
  1854. X    } else {
  1855. X    t = termtab;
  1856. X    while(t && t->nxt)
  1857. X      t = t->nxt;
  1858. X    t->nxt = n;
  1859. X    }
  1860. X    
  1861. X    return(0);
  1862. X}
  1863. X
  1864. X/*
  1865. X * Listen for a response.
  1866. X */
  1867. Xvoid qterm_listen(q)
  1868. X     struct termtable *q;
  1869. X{
  1870. X    static int i, len;
  1871. X    register char c;
  1872. X    char end;
  1873. X    
  1874. X    (void) alarm((unsigned)0);
  1875. X    (void) strcpy(recvbuf, "");
  1876. X    i = 0;
  1877. X    
  1878. X    len = strlen(q->qt_recvstr);
  1879. X    
  1880. X    if (len) {
  1881. X    end = q->qt_recvstr[len - 1];
  1882. X    } else {
  1883. X    end = 'c'; /* Fairly standard ANSI default */
  1884. X    }
  1885. X    
  1886. X    dprintf("\nlisten for %s\t [ len = %d, end = `%c' ]\n", 
  1887. X        decode(q->qt_recvstr), len, end);
  1888. X    
  1889. X    /*
  1890. X     * If we don't get an initial character, bounce out
  1891. X     * of here and finish with done(0).
  1892. X     */
  1893. X    if (setjmp(env)) {
  1894. X    if (found) {
  1895. X        done(0);
  1896. X        /*NOTREACHED*/
  1897. X    }
  1898. X    (void) fflush(stdin);
  1899. X    proctab(q->nxt);
  1900. X    } else {
  1901. X    (void) signal(SIGALRM, wakeup);
  1902. X    (void) alarm((unsigned)almwait);
  1903. X    recvbuf[0] = getch();
  1904. X    (void) alarm((unsigned)0);
  1905. X    }
  1906. X    
  1907. X    /*
  1908. X     * Read in remaining response.  Loop until ending character
  1909. X     * is received or until alarm goes off.  If towait is set,
  1910. X     * then let alarm go off.
  1911. X     */
  1912. X    for (i = 1, c = -1; (!towait && (c != end)) || towait; ) {
  1913. X    if (setjmp(env))  {
  1914. X        recvbuf[i] = (char) NULL;
  1915. X        return;
  1916. X    } else {
  1917. X        (void) signal(SIGALRM, wakeup);
  1918. X        (void) alarm((unsigned)almwait);
  1919. X        c = getch();
  1920. X        (void) alarm((unsigned)0);
  1921. X    }
  1922. X    recvbuf[i++] = c;
  1923. X    }
  1924. X    recvbuf[i] = (char) NULL;
  1925. X    
  1926. X    dprintf("listen done.  read %d chars.\n\n", i);
  1927. X}
  1928. X
  1929. X/*
  1930. X * Print a message since we didn't recognize this terminal.
  1931. X */
  1932. Xvoid notrecognized()
  1933. X{
  1934. X    char *envterm;
  1935. X    
  1936. X    if ((envterm = getenv("TERM")) == NULL)
  1937. X    envterm = "dumb";
  1938. X    
  1939. X    if (!quiet)
  1940. X    (void) fprintf(stderr, 
  1941. X               "Terminal NOT recognized - defaults to \"%s\".\n",
  1942. X               envterm);
  1943. X    
  1944. X    puts(envterm);
  1945. X}
  1946. X
  1947. X/*
  1948. X * Process entries in the termtable.
  1949. X */
  1950. Xvoid proctab(t)
  1951. X     struct termtable *t;
  1952. X{
  1953. X    int st = FALSE;
  1954. X    static int firsttime = TRUE;
  1955. X    static struct termtable *lastt;
  1956. X    
  1957. X    dprintf("\n[ Processing entries ] \n");
  1958. X    
  1959. X    if (firsttime) {
  1960. X    t = termtab;
  1961. X    lastt = NULL;
  1962. X    }
  1963. X    
  1964. X    while ((!found || do_usrtabfile) && t && t->qt_sendstr && !st) {
  1965. X    /*
  1966. X     * If this is our first time or the sendstr is the same as
  1967. X     * last time, don't send it again.
  1968. X     */
  1969. X    if (always_send || firsttime || lastt == NULL || 
  1970. X        strcmp(t->qt_sendstr, lastt->qt_sendstr) != 0) {
  1971. X        
  1972. X        if (firsttime)
  1973. X        firsttime = FALSE;
  1974. X        
  1975. X        if (watch_chars)
  1976. X        (void) printf("Send: %s\n", decode(t->qt_sendstr));
  1977. X
  1978. X        (void) fflush(stdin);
  1979. X        (void) fprintf(stderr, "%s", t->qt_sendstr);
  1980. X        (void) fflush(stderr);
  1981. X        
  1982. X        lastt = t;
  1983. X        (void) qterm_listen(t);
  1984. X        
  1985. X        if (watch_chars)
  1986. X        (void) printf("\tRead: %s\n", decode(recvbuf));
  1987. X    }
  1988. X    
  1989. X    st = prinfo(compare(recvbuf), FALSE);
  1990. X    
  1991. X    lastt = t;
  1992. X    t = t->nxt;
  1993. X    }
  1994. X    
  1995. X    if (!found)
  1996. X    notrecognized();
  1997. X    
  1998. X    done(0);
  1999. X    /*NOTREACHED*/
  2000. X}
  2001. X
  2002. Xchar *fixctl(str, rex)
  2003. X     char *str;
  2004. X     int rex;
  2005. X{
  2006. X    register int i;
  2007. X    static char buf[BUFSIZ];
  2008. X    
  2009. X    for (i = 0; str && *str; ) {
  2010. X    switch (*str) {
  2011. X        
  2012. X      case '\\':
  2013. X        if (isdigit(*++str)) {
  2014. X        buf[i] = 0;
  2015. X        while (isdigit(*str))
  2016. X            buf[i] = (char) (((int)buf[i] * 8) + 
  2017. X                     (int)*str++ - (int) '0');
  2018. X        i++;
  2019. X        } else
  2020. X        buf[i++] = *str++;
  2021. X        continue;
  2022. X        
  2023. X      case '^':
  2024. X        switch (*++str) {
  2025. X          case '?':
  2026. X        buf[i++] = '\177';
  2027. X        break;
  2028. X          default:
  2029. X        buf[i++] = *str & 037;
  2030. X        break;
  2031. X        }
  2032. X        break;
  2033. X        
  2034. X        /* Special R.E. symbols */
  2035. X      case '[':
  2036. X      case '*':
  2037. X      case '.':
  2038. X      case '$':
  2039. X      case '{':
  2040. X      case '(':
  2041. X        if (rex)
  2042. X          buf[i++] = '\\';
  2043. X        
  2044. X      default:
  2045. X        buf[i++] = *str;
  2046. X    }
  2047. X    *++str;
  2048. X    }
  2049. X    
  2050. X    buf[i] = (char) NULL;
  2051. X    
  2052. X    return(buf);
  2053. X}
  2054. X
  2055. X/*
  2056. X * xmalloc - Do a malloc with error checking.
  2057. X */
  2058. Xchar *xmalloc(size)
  2059. X     int size;
  2060. X{
  2061. X    char *p;
  2062. X    
  2063. X    if ((p = malloc((unsigned) size)) == NULL) {
  2064. X    myperror("malloc");
  2065. X    done(1);
  2066. X    /*NOTREACHED*/
  2067. X    }
  2068. X    
  2069. X    return(p);
  2070. X}
  2071. X
  2072. X#ifdef HAS_VARARGS
  2073. Xvoid dprintf(va_alist)
  2074. X     va_dcl
  2075. X{
  2076. X    va_list args;
  2077. X    char *fmt;
  2078. X
  2079. X    if (!debug)
  2080. X    return;
  2081. X
  2082. X    va_start(args);
  2083. X    fmt = (char *) va_arg(args, char *);
  2084. X    (void) vprintf(fmt, args);
  2085. X    va_end(args());
  2086. X    (void) fflush(stdout);
  2087. X}
  2088. X
  2089. X#else /*HAS_VARARGS*/
  2090. X
  2091. Xvoid dprintf(fmt, a1, a2, a3, a4, a5, a6)
  2092. X     char *fmt;
  2093. X{
  2094. X    if (!debug)
  2095. X    return;
  2096. X
  2097. X    (void) printf(fmt, a1, a2, a3, a4, a5, a6);
  2098. X    (void) fflush(stdout);
  2099. X}
  2100. X#endif /*HAS_VARARGS*/
  2101. X
  2102. X/*
  2103. X * Catch kill signals and cleanup.
  2104. X */
  2105. Xvoid catch()
  2106. X{
  2107. X    done(2);
  2108. X    /*NOTREACHED*/
  2109. X}
  2110. X
  2111. Xvoid wakeup()
  2112. X{
  2113. X    dprintf("wakeup called\n");
  2114. X    longjmp(env, 1);
  2115. X}
  2116. X
  2117. Xvoid myperror(msg)
  2118. X     char *msg;
  2119. X{
  2120. X    (void) fprintf(stderr, "%s: ", progname);
  2121. X    perror(msg);
  2122. X}
  2123. X
  2124. X/*
  2125. X * Reset terminal and exit with status s.
  2126. X */
  2127. Xvoid done(s)
  2128. X     int s;
  2129. X{
  2130. X    resetmodes();
  2131. X    exit(s);
  2132. X}
  2133. END_OF_FILE
  2134.   if test 24777 -ne `wc -c <'qterm.c'`; then
  2135.     echo shar: \"'qterm.c'\" unpacked with wrong size!
  2136.   fi
  2137.   # end of 'qterm.c'
  2138. fi
  2139. echo shar: End of archive 1 \(of 2\).
  2140. cp /dev/null ark1isdone
  2141. MISSING=""
  2142. for I in 1 2 ; do
  2143.     if test ! -f ark${I}isdone ; then
  2144.     MISSING="${MISSING} ${I}"
  2145.     fi
  2146. done
  2147. if test "${MISSING}" = "" ; then
  2148.     echo You have unpacked both archives.
  2149.     rm -f ark[1-9]isdone
  2150. else
  2151.     echo You still must unpack the following archives:
  2152.     echo "        " ${MISSING}
  2153. fi
  2154. exit 0
  2155. exit 0 # Just in case...
  2156.